"""Program ``faust models`` used to list models available."""
from operator import attrgetter
from typing import Any, Callable, Sequence, Type, cast
from faust.models import registry
from faust.types import ModelT
from .base import AppCommand, option

__all__ = ['models']


class models(AppCommand):
    """List all available models as a tabulated list."""

    title = 'Models'
    headers = ['name', 'help']
    sortkey = attrgetter('_options.namespace')

    options = [
        option('--builtins/--no-builtins', default=False),
    ]

    async def run(self, *, builtins: bool) -> None:
        """Dump list of available models in this application."""
        self.say(
            self.tabulate(
                [self.model_to_row(model) for model in self.models(builtins)],
                headers=self.headers,
                title=self.title,
            ))

    def models(self, builtins: bool) -> Sequence[Type[ModelT]]:
        """Convert list of models to terminal table rows."""
        sortkey = cast(Callable[[Type[ModelT]], Any], self.sortkey)
        return [
            model for model in sorted(registry.values(), key=sortkey)
            if not model._options.namespace.startswith('@') or builtins
        ]

    def model_to_row(self, model: Type[ModelT]) -> Sequence[str]:
        """Convert model fields to terminal table columns."""
        return [
            self.bold_tail(self._name(model)),
            self.dark(self._help(model)),
        ]

    def _name(self, model: Type[ModelT]) -> str:
        return self.abbreviate_fqdn(model._options.namespace)

    def _help(self, model: Type[ModelT]) -> str:
        return model.__doc__ or '<N/A>'
